package luke.audio.generation;


import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import luke.audio.analyzer.BeatDetector;

import luke.audio.metadata.AudioMetadataReader;
import luke.audio.metadata.Song;
import luke.audio.metadata.SongMetadataExtractor;
import luke.audio.processor.*;
import luke.audio.processing.*;
import luke.audio.processor.AudioSpeedChanger;
import luke.core.config.AppDataManager; // 添加AppDataManager导入
import luke.core.logging.LogUtil;
import luke.core.utils.JsonUtils;
import luke.media.image.ImageCrawler;
import luke.media.video.*;
import luke.media.video.PlaylistOverlayVideoGenerator; // 添加PlaylistOverlayVideoGenerator导入
import luke.system.callback.ProgressCallback;

import javax.imageio.ImageIO;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import com.google.gson.reflect.TypeToken;

public class RunningMusicGenerator {

    // 用于存储处理后的歌曲列表
    private List<Song> processedSongs = new ArrayList<>();
    // 用于存储处理后音频路径与原始音频路径的映射关系
    private Map<String, String> audioPathMapping = new HashMap<>();

    // 添加全局完成计数器
    private AtomicInteger globalCompletedCounter = new AtomicInteger(0);

    // 添加停止标志
    private volatile boolean isStopping = false;
    private double progressRatio;
    private List<Song> completedBPMSongs;
    private MixResult mixResult;

    // 创建一个包装类来同时返回选中的歌曲列表、混合音频路径、播放列表内容和M3U文件路径
    public static class MixResult {
        private final List<Song> finalSelectedSongs;// 选中的歌曲列表
        private final String mixAudioPath;// 混合音频路径
        private final int totalDuration;// 混合音频总时长（毫秒）
        private final List<String> displayListContent; // 播放列表内容
        private final String m3uFilePath; // M3U文件路径


        public MixResult(List<Song> finalSelectedSongs, String mixAudioPath, int totalDuration, List<String> displayListContent, String m3uFilePath) {
            this.finalSelectedSongs = finalSelectedSongs;
            this.mixAudioPath = mixAudioPath;
            this.displayListContent = displayListContent != null ? new ArrayList<>(displayListContent) : new ArrayList<>();
            this.m3uFilePath = m3uFilePath != null ? m3uFilePath : "";
            this.totalDuration = totalDuration;
        }

        public int getTotalDuration() {
            return totalDuration;
        }

        public List<Song> getFinalSelectedSongs() {
            return finalSelectedSongs;
        }

        public String getMixAudioPath() {
            return mixAudioPath;
        }

        public List<String> getDisplayListContent() {
            return new ArrayList<>(displayListContent);
        }

        public String getM3uFilePath() {
            return m3uFilePath;
        }
    }

    private List<File> filesToProcess; // 要处理的歌曲文件
    private double targetBpm; // 目标BPM
    private File outputDir; // 输出目录
    private File tempDir; // 临时目录
    private double plannedDuration; // 总时长（分钟）
    private float beatVolume; // 鼓点音量（0.0-1.0）
    private int beatSoundType = 0;

    private MusicGenerationParams params;

    private String videoResolution; // 视频分辨率（如"1080p"）
    private boolean isLandscape; // 是否为横屏模式
    private String videoStyle; // 视频样式（"slideshow"或"spectrum"）
    private String generationType; // 生成类型（"single", "mix", "mix_video"）
    private int parallelTaskCount; // 并行任务数量
    private boolean truncateExceedingFiles; // 是否截断超出时长的文件
    private SongMetadataExtractor.AnalysisProgressCallback callback; // 分析进度回调

    public void generateRunningTracks(MusicGenerationParams params, SongMetadataExtractor.AnalysisProgressCallback callback) throws Exception {
        // 重置停止标志
        isStopping = false;

        // 重置processedSongs和audioPathMapping
        processedSongs.clear();
        audioPathMapping.clear();

        String debugInfo = "=================== 开始生成跑步音乐 ===================\n" +
                "目标BPM: " + params.getTargetBpm() + "\n" +
                "歌曲数量: " + params.getFilesToProcess().size() + "\n" +
                "生成类型: " + params.getGenerationType() + "\n" +
                "输出目录: " + params.getOutputDir().getAbsolutePath() + "\n" +
                "临时目录: " + params.getTempDir().getAbsolutePath() + "\n" +
                "计划时长: " + params.getPlannedDuration() + " 分钟\n" +
                "鼓点音量: " + params.getBeatVolume() + "\n" +
                "背景音量: " + params.getBackgroundVolume() + "\n" +  // 添加背景音量信息
                "鼓点声音类型: " + params.getBeatSoundType() + "\n" +
                "视频分辨率: " + params.getVideoResolution() + "\n" +
                "视频样式: " + params.getVideoStyle() + "\n" +
                "并行任务数量: " + params.getParallelTaskCount() + "\n" +
                "是否截断超出时长的文件: " + params.isTruncateExceedingFiles() + "\n" +  // 添加调试信息
                "工作目录: " + System.getProperty("user.dir") + "\n" +
                "Java临时目录: " + System.getProperty("java.io.tmpdir") + "\n" +
                "===============================================";

        LogUtil.debug("RunningMusicGenerator", "generateRunningTracks", debugInfo);
        this.videoStyle = params.getVideoStyle();
        this.beatSoundType = params.getBeatSoundType();
        this.beatVolume = params.getBeatVolume();
        this.parallelTaskCount = params.getParallelTaskCount();//并行任务数量
        this.filesToProcess = params.getFilesToProcess();
        this.targetBpm = params.getTargetBpm();
        this.outputDir = params.getOutputDir();
        this.tempDir = params.getTempDir();
        this.plannedDuration = params.getPlannedDuration();
        this.truncateExceedingFiles = params.isTruncateExceedingFiles();
        this.callback = callback;
        this.videoResolution = params.getVideoResolution();
        this.isLandscape = params.isLandscape();
        this.generationType = params.getGenerationType();
        this.params = params;
        writeProcessingLog("参数初始化完成", debugInfo);

        writeProcessingLog("生成跑步音乐开始", debugInfo);

        progressRatio = 1.0 / 2;
        switch (generationType) {
            case "single":
                progressRatio = 1.0 / 2;
                break;
            case "mix":
                progressRatio = 1.0 / 3;
                break;
            case "mix_video":
                progressRatio = 1.0 / 4;
                break;
            default:
                throw new IllegalArgumentException("未知的生成类型: " + generationType);
        }
        //歌曲预处理
        preProcessSongs();
        //生成单曲
        generateSingleTrack();
        //生成串烧
        generateMix();
        //生成视频
        generateRunningVideo();

        writeProcessingLog("生成跑步音乐结束", debugInfo);
        callback.onOtherTaskComplete();
    }

    /**
     * 歌曲文件预处理(分析文件的bpm)
     *
     * @throws Exception
     */
    public void preProcessSongs() throws Exception {
        //预处理歌曲列表，获取歌曲的bpm
        SongMetadataExtractor songMetadataExtractor = SongMetadataExtractor.getInstance();

        //分析完成标识
        final boolean[] isAnalysisComplete = {false};
        SongMetadataExtractor.AnalysisProgressCallback progressCallback = new SongMetadataExtractor.AnalysisProgressCallback() {
            @Override
            public void onProgressUpdate(String message, int progress, File currentFile) {
                // 检查是否需要停止
                if (isStopping) {
                    try {
                        throw new InterruptedException("任务已被取消");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 调用外部回调
                if (callback != null) {
                    callback.onProgressUpdate(message, (int) Math.round(progress * progressRatio), currentFile);
                    if (progress == 100) {
                        //分析完成后标识
                        isAnalysisComplete[0] = true;
                    }
                }
            }

            @Override
            public void onFileAnalysisComplete(File file) {
                callback.onFileAnalysisComplete(file);
                // 文件分析完成，不打印日志以减少干扰
            }

            @Override
            public void onBPMTaskComplete() {
                // 调用任务完成回调
                if (callback != null) {
                    callback.onBPMTaskComplete();
                }
            }
        };
        songMetadataExtractor.batchExtractMetadata(filesToProcess, 1, progressCallback);
        //等待bpm分析完成...
        while (!isAnalysisComplete[0]) {
            Thread.sleep(100);
        }
        //获取song,取出已经分析完成的歌曲
        Map<File, Song> songData = songMetadataExtractor.getSongData();
        // 过滤出分析完成的歌曲，保持原始顺序
        completedBPMSongs = new ArrayList<>();
        for (File file : filesToProcess) {
            Song song = songData.get(file);
            if (song != null && song.getBpm() != 0) {
                completedBPMSongs.add(song);
            }
        }

        // 打印completedBPMSongs和filesToProcess列表的歌曲文件名，用于调试列表顺序
        LogUtil.debug("RunningMusicGenerator", "preProcessSongs", "filesToProcess文件名列表: " +
                filesToProcess.stream().map(File::getName).collect(Collectors.toList()));
        LogUtil.debug("RunningMusicGenerator", "preProcessSongs", "completedBPMSongs文件名列表: " +
                completedBPMSongs.stream().map(song -> new File(song.getAudioPath()).getName()).collect(Collectors.toList()));

    }

    /**
     * 生成单曲
     *
     * @throws Exception
     */
    public void generateSingleTrack() throws Exception {
        // 使用指定并行度的ForkJoinPool进行并行处理
        ForkJoinPool forkJoinPool = new ForkJoinPool(parallelTaskCount);
        SongMetadataExtractor.AnalysisProgressCallback progressCallback = new SongMetadataExtractor.AnalysisProgressCallback() {
            @Override
            public void onProgressUpdate(String message, int progress, File currentFile) {
                // 检查是否需要停止
                if (isStopping) {
                    try {
                        throw new InterruptedException("任务已被取消");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 记录进度值以便调试
                // 调用外部回调
                if (callback != null) {
                    int adjustedProgress = (int) Math.round(100 * progressRatio + progressRatio * progress);
                    callback.onProgressUpdate(message, adjustedProgress, currentFile);
                }
            }

        };
        try {
            // 重置全局完成计数器
            globalCompletedCounter.set(0);

            // 创建原子计数器跟踪已完成的歌曲数量
            AtomicInteger completedSongs = new AtomicInteger(0);

            // 提交任务并等待完成
            forkJoinPool.submit(() -> {
                SongProcessingTask task = new SongProcessingTask(params, completedBPMSongs, this, progressCallback);
                task.compute();
            }).get(); // 阻塞直到任务完成

            // 检查任务是否被取消
            if (Thread.currentThread().isInterrupted() || isStopping) {
                throw new InterruptedException("任务已被取消");
            }

            // 等待所有任务完成并验证processedSongs
            for (int i = 0; i < processedSongs.size(); i++) {
                Song song = processedSongs.get(i);
                if (song != null) {
                } else {
                }
            }
        } finally {
            forkJoinPool.shutdown();
        }
    }

    /**
     * 生成串烧音频
     */
    private void generateMix() throws Exception {
        LogUtil.debug("RunningMusicGenerator", "generateRunningTracks", "开始生成串烧音频...");
        SongMetadataExtractor.AnalysisProgressCallback progressCallback = new SongMetadataExtractor.AnalysisProgressCallback() {
            @Override
            public void onProgressUpdate(String message, int progress, File currentFile) {
                // 检查是否需要停止
                if (isStopping) {
                    try {
                        throw new InterruptedException("任务已被取消");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 记录进度值以便调试
                LogUtil.debug("RunningMusicGenerator.generateMix", "onProgressUpdate", "进度回调 - 消息: " + message + ", 进度: " + progress + ", progressRatio: " + progressRatio);
                // 调用外部回调
                if (callback != null) {
                    int adjustedProgress = (int) Math.round(2 * 100 * progressRatio + progressRatio * progress);
                    LogUtil.debug("RunningMusicGenerator.generateMix", "onProgressUpdate", "调整后的进度: " + adjustedProgress);
                    callback.onProgressUpdate(message, adjustedProgress, currentFile);
                }
            }

        };
        if (generationType.equals("mix") || generationType.equals("mix_video")) {
            mixResult = createRunningMix(progressCallback);
        }
    }

    /**
     * 生成跑步视频
     */
    private void generateRunningVideo() throws Exception {
        SongMetadataExtractor.AnalysisProgressCallback progressCallback = new SongMetadataExtractor.AnalysisProgressCallback() {
            @Override
            public void onProgressUpdate(String message, int progress, File currentFile) {
                // 检查是否需要停止
                if (isStopping) {
                    try {
                        throw new InterruptedException("任务已被取消");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 记录进度值以便调试
                // 调用外部回调
                if (callback != null) {
                    int adjustedProgress = (int) Math.round(3 * 100 * progressRatio + progressRatio * progress);
                    callback.onProgressUpdate(message, adjustedProgress, currentFile);
                }
            }

        };
        if (generationType.equals("mix_video")) {
            //生成视频
            createRunningVideo(progressCallback);
        }

    }

    /**
     * 设置停止标志，用于外部中断操作
     */
    public void stopGeneration() {
        isStopping = true;
    }

    /**
     * 创建跑步串烧
     * 将处理好的歌曲按顺序合并成一首长音乐
     *
     * @return 包含选中歌曲列表和混合音频路径的MixResult对象
     * @throws Exception 处理过程中可能出现的异常
     */
    private MixResult createRunningMix(SongMetadataExtractor.AnalysisProgressCallback progressCallback) throws Exception {
        LogUtil.debug("RunningMusicGenerator", "createRunningMix", "开始创建跑步串烧，歌曲数量: " + processedSongs.size() + "，是否截断超出时长的文件: " + truncateExceedingFiles);
        // 直接使用处理好的Song对象，它们已经包含了变速后的信息
        List<Song> processedSongList = new ArrayList<>(processedSongs); // 创建副本以避免并发修改问题

        // 过滤掉null值
        processedSongList.removeIf(Objects::isNull);

        // 控制总时长，不超过最大时长
        List<Song> finalSelectedSongs = new ArrayList<>();//过滤后的歌曲列表
        int totalDuration = 0;

        // 按顺序选择歌曲
        // 只有在勾选了截断选项时，才需要判断歌曲时长是否超过最大时长
        if (truncateExceedingFiles) {
            // 如果启用了截断功能，则按顺序选择歌曲，直到达到最大时长
            // plannedDuration是以分钟为单位，需要转换为毫秒进行比较
            long plannedDurationMs = (long) (plannedDuration * 60 * 1000);
            for (Song song : processedSongList) {
                if (totalDuration + song.getDuration() <= plannedDurationMs) {
                    finalSelectedSongs.add(song);
                    totalDuration += song.getDuration();
                } else {
                    break;
                }
            }
        } else {
            // 如果没有启用截断功能，则添加所有歌曲，不需要考虑最大时长限制
            for (Song song : processedSongList) {
                finalSelectedSongs.add(song);
                totalDuration += song.getDuration();
            }
        }

        LogUtil.debug("RunningMusicGenerator", "createRunningMix", "选中歌曲数量: " + finalSelectedSongs.size() + "，总时长: " + totalDuration + "ms");


        //  创建串烧输出路径
        File outputMixDir = new File(outputDir, "run_mix");
        outputMixDir.mkdirs();
        // 如果targetBpm为-1，表示保持原速，使用"original"作为标识
        String bpmLabel = (targetBpm == -1) ? "original" : String.format("%.0f", targetBpm);
        // 使用更易读的日期时间格式生成文件名
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
        String timestamp = dateFormat.format(new Date());
        File outputMixPath = new File(outputMixDir, "BPM" + bpmLabel + "RUN_MIX__" + timestamp + ".wav");

        // 创建播放列表
        List<String> displayList = createDisplayList(finalSelectedSongs, outputMixDir);

        // 读取播放列表内容
        File playlistFile = new File(outputMixDir, "playlist.m3u");
        List<String> displayListContent = new ArrayList<>();
        if (playlistFile.exists()) {
            try {
                List<String> lines = Files.readAllLines(playlistFile.toPath());
                // 处理M3U文件内容，只保留有效行（非注释、非空行、非M3U头）
                for (String line : lines) {
                    // 跳过M3U文件头和注释行
                    if (!line.startsWith("#") && !line.trim().isEmpty()) {
                        displayListContent.add(line);
                    }
                }
            } catch (IOException e) {
                LogUtil.error("RunningMusicGenerator", "createRunningMix", "读取播放列表文件失败: " + e.getMessage());
            }
        }

        List<String> inputFiles = finalSelectedSongs.stream()
                .map(song -> song.getAudioPath())
                .collect(Collectors.toList());

        // 生成音频文件列表签名
        List<File> audioFiles = inputFiles.stream().map(File::new).collect(Collectors.toList());
        String signature = generateAudioListSignature(audioFiles);//生成音频文件列表的签名
        LogUtil.debug("RunningMusicGenerator", "createRunningMix", "音频文件列表签名: " + signature);


        boolean useCache = signature != null;//检查是否有签名，如果有则使用缓存，否则不使用缓存
        // 检查是否有缓存的合并音频文件
        String cachedMergedAudioPath = null;
        if (useCache) {//检查是否有签名，如果有则使用缓存，否则不使用缓存
            cachedMergedAudioPath = getCachedMergedAudioPath(signature);//获取缓存的合并音频文件
            if (cachedMergedAudioPath != null) {
                LogUtil.debug("RunningMusicGenerator", "createRunningMix", "找到缓存的合并音频文件: " + cachedMergedAudioPath);
                // 检查缓存文件是否存在
                File cachedFile = new File(cachedMergedAudioPath);
                if (cachedFile.exists()) {
                    File newOutputFile = new File(outputMixPath.getAbsolutePath());
                    // 重命名缓存文件为新的输出路径
                    if (cachedFile.renameTo(newOutputFile)) {
                        LogUtil.debug("RunningMusicGenerator", "createRunningMix", "已将缓存文件重命名为: " + outputMixPath.getAbsolutePath());
                        // 返回选中的歌曲列表、重命名后的混合音频路径、播放列表内容和M3U文件路径
                        return new MixResult(finalSelectedSongs, outputMixPath.getAbsolutePath(), totalDuration, displayListContent, playlistFile.getAbsolutePath());
                    }
                }
            }
        }

        // 使用AudioMixer连接所有音频文件
        JavaCVProcessor javaCVProcessor = new JavaCVProcessor();
        try {
            if (!inputFiles.isEmpty()) {
                LogUtil.debug("RunningMusicGenerator", "createRunningMix", "开始合并音频文件...");
                // 将List<String>转换为List<File>
                List<File> audioFilesToMerge = inputFiles.stream()
                        .map(File::new)
                        .collect(Collectors.toList());

                // 添加进度回调：开始合并音频
                if (progressCallback != null) {
                    progressCallback.onProgressUpdate("正在合并音频文件...", 0, outputMixPath);
                }

                // 在合并过程中添加更多进度反馈
                javaCVProcessor.concatAudioFilesWithJavaCV(audioFilesToMerge, outputMixPath.getAbsolutePath(), new ProgressCallback() {
                    @Override
                    public void onProgress(String message, double progress) {
                        double mappedProgress = progress;
                        if (progressCallback != null) {
                            progressCallback.onProgressUpdate("合并音频: " + message, (int) Math.round(mappedProgress), outputMixPath);
                        }
                    }
                });

                // 添加进度回调：音频合并完成
                if (progressCallback != null) {
                    progressCallback.onProgressUpdate("音频文件合并完成", 100, outputMixPath);
                }

                // 验证输出文件是否存在且不为空
                if (outputMixPath.exists() && outputMixPath.length() > 0) {
                    LogUtil.debug("RunningMusicGenerator", "createRunningMix", "合并后的音频文件验证通过，大小: " + outputMixPath.length() + " 字节");

                    // 将合并后的音频文件路径保存到缓存
                    if (useCache) {
                        saveMergedAudioPathToCache(signature, outputMixPath.getAbsolutePath());//保存合并后的音频文件路径到缓存
                        LogUtil.debug("RunningMusicGenerator", "createRunningMix", "已将合并音频文件路径保存到缓存");
                    }
                } else {
                    LogUtil.error("RunningMusicGenerator", "createRunningMix", "合并后的音频文件不存在或为空");
                    throw new IOException("合并后的音频文件不存在或为空: " + outputMixPath.getAbsolutePath());
                }
            } else {
                LogUtil.debug("RunningMusicGenerator", "createRunningMix", "没有选中的歌曲用于合并");
            }
        } catch (Exception e) {
            LogUtil.error("RunningMusicGenerator", "createRunningMix", "合并歌曲时出错: " + e.getMessage());
            LogUtil.error("RunningMusicGenerator", "createRunningMix", "合并歌曲时出错的堆栈信息: " + java.util.Arrays.toString(e.getStackTrace()));
            throw new Exception("合并歌曲时出错", e);
        }

        LogUtil.debug("RunningMusicGenerator", "createRunningMix", "歌曲合并完成: " + outputMixPath);

        // 返回选中的歌曲列表、混合音频路径、播放列表内容和M3U文件路径
        return new MixResult(finalSelectedSongs, outputMixPath.getAbsolutePath(), totalDuration, displayListContent, playlistFile.getAbsolutePath());
    }

    /**
     * 创建播放列表文件
     *
     * @param songs     歌曲列表
     * @param outputDir 输出目录
     * @throws IOException IO异常
     */
    private List<String> createDisplayList(List<Song> songs, File outputDir) throws IOException {
        // 创建播放列表内容
        StringBuilder playlistContent = new StringBuilder();
        // 创建显示列表
        List<String> displayList = new ArrayList<>();
        // 记录当前时间（毫秒）
        int currentTime = 0;

        // 遍历歌曲列表
        for (int i = 0; i < songs.size(); i++) {
            Song song = songs.get(i);

            // 获取处理后的音频路径
            String processedAudioPath = song.getAudioPath();

            // 从audioPathMapping获取原始音频路径
            String originalAudioPath = audioPathMapping.get(processedAudioPath);
            if (originalAudioPath == null) {
                originalAudioPath = processedAudioPath; // 如果没有映射，使用处理后的路径作为原始路径
            }

            // 读取音频文件的元数据
            AudioMetadataReader.AudioMetadata metadata = AudioMetadataReader.readMetadata(originalAudioPath);

            // 获取歌曲时长
            int duration = song.getDuration();

            // 打印调试信息
            System.out.println("处理歌曲 " + i + ": " + originalAudioPath + ", 时长: " + duration + "ms");

            // 确保最小时间间隔为1秒（1000ms）
            int actualDuration = Math.max(duration, 1000);

            // 格式化开始和结束时间
            String startTime = formatTime(currentTime);
            String endTime = formatTime(currentTime + actualDuration);

            // 添加到播放列表
            String title = metadata.getTitle();
            // 如果标题为空，则使用文件名作为标题
            if (title == null || title.isEmpty()) {
                // 从文件路径中提取文件名（不含扩展名）作为标题
                File audioFile = new File(originalAudioPath);
                String fileName = audioFile.getName();
                int lastDotIndex = fileName.lastIndexOf('.');
                if (lastDotIndex > 0) {
                    title = fileName.substring(0, lastDotIndex);
                } else {
                    title = fileName; // 如果没有扩展名，使用完整文件名
                }
            }
            String playlistEntry = String.format("[%s-%s] %s", startTime, endTime, title);
            // 添加到显示列表
            displayList.add(playlistEntry);
            playlistContent.append(playlistEntry).append("\n");
            System.out.println("添加播放列表项: " + playlistEntry);

            // 更新当前时间
            currentTime += actualDuration;
        }

        // 保存播放列表到文件
        File playlistFile = new File(outputDir, "playlist.m3u");
        Files.write(playlistFile.toPath(), playlistContent.toString().getBytes());

        // 添加调试日志，打印创建的播放列表内容
        System.out.println("创建的播放列表内容:");
        String[] lines = playlistContent.toString().split("\n");
        for (int i = 0; i < lines.length; i++) {
            System.out.println("播放列表行 " + i + ": " + lines[i]);
        }
        System.out.println("播放列表文件路径: " + playlistFile.getAbsolutePath());
        return displayList;
    }

    /**
     * 格式化毫秒时间为HH:mm:ss格式
     *
     * @param millis 毫秒时间
     * @return 格式化后的时间字符串
     */
    private String formatTime(int millis) {
        int totalSeconds = millis / 1000;


        int hours = totalSeconds / 3600;
        int minutes = (totalSeconds % 3600) / 60;
        int seconds = totalSeconds % 60;

        // 使用三位数格式，避免出现单数字
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    // 并行处理任务类
    private static class SongProcessingTask extends RecursiveAction {
        private final List<Song> completedBPMSongs;            // 待处理的歌曲列表
        private final double targetBpm;            // 目标BPM（每分钟节拍数）
        private final File outputDir;              // 输出目录（修改为File类型）
        private final File tempDir;             // 临时目录
        private final int totalSongs;              // 总歌曲数
        private final String generationType;        // 生成类型（"single"、"mix"、"mix_video"）
        private final List<Song> processedSongs;   // 处理后的歌曲列表引用
        private final Map<String, String> audioPathMapping; // 音频路径映射关系引用
        private int beatSoundType;           // 鼓点音效类型
        private float beatVolume;            // 鼓点音量
        private float backgroundVolume;      // 背景音量
        private final List<Integer> originalIndices; // 原始索引列表，用于保持顺序
        private final SongMetadataExtractor.AnalysisProgressCallback progressCallback; // 进度回调
        private final RunningMusicGenerator outerInstance; // 外部类实例引用
        private MusicGenerationParams params;

        public SongProcessingTask(MusicGenerationParams params,
                                  List<Song> completedBPMSongs,
                                  RunningMusicGenerator outerInstance,
                                  SongMetadataExtractor.AnalysisProgressCallback progressCallback) {
            this.completedBPMSongs = completedBPMSongs;// 待处理的歌曲列表
            this.targetBpm = params.getTargetBpm();// 目标BPM
            this.outputDir = params.getOutputDir();// 输出目录
            this.tempDir = params.getTempDir();// 临时目录
            this.totalSongs = completedBPMSongs.size();// 总歌曲数
            this.generationType = params.getGenerationType();// 生成类型
            this.progressCallback = progressCallback;// 进度回调
            this.outerInstance = outerInstance;// 外部类实例引用
            this.beatSoundType = params.getBeatSoundType();// 鼓点音效类型
            this.beatVolume = params.getBeatVolume();// 鼓点音量
            this.backgroundVolume = params.getBackgroundVolume();// 背景音量
            this.params = params;// 参数

            // 引用外部类的processedSongs和audioPathMapping
            this.processedSongs = outerInstance.processedSongs;
            this.audioPathMapping = outerInstance.audioPathMapping;

            // 初始化原始索引列表
            this.originalIndices = new ArrayList<>();
            for (int i = 0; i < this.completedBPMSongs.size(); i++) {
                this.originalIndices.add(i);
            }
        }


        @Override
        protected void compute() {
            // 检查线程是否被中断
            if (Thread.currentThread().isInterrupted()) {
                return;
            }

            // 检查外部停止标志
            try {
                // 直接访问外部类实例的isStopping字段
                boolean isStopping = outerInstance.isStopping;

                if (isStopping) {
                    return;
                }
            } catch (Exception e) {
                LogUtil.error("RunningMusicGenerator.SongProcessingTask", "compute", "检查停止标志时出错: " + e.getMessage());
            }

            if (completedBPMSongs.size() <= 1) {
                // 处理单首歌曲
                Song processedSong = processSong(completedBPMSongs.get(0));
                if (processedSong != null) {
                    // 使用同步块确保线程安全地添加到正确位置
                    synchronized (processedSongs) {
                        // 确保processedSongs足够大以容纳当前索引
                        int targetIndex = originalIndices.get(0);
                        while (processedSongs.size() <= targetIndex) {
                            processedSongs.add(null);
                        }
                        processedSongs.set(targetIndex, processedSong);
                    }
                } else {
                    LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "compute", "处理歌曲失败，返回null");
                }

                // 更新全局进度
                int completed = outerInstance.globalCompletedCounter.incrementAndGet();
                // 获取外部类实例的总歌曲数
                int totalSongsForProgress = outerInstance.completedBPMSongs.size();
                // 修复进度计算，确保使用浮点数运算
                double progress = (completed * 100.0 / totalSongsForProgress);

                // 添加日志输出以便调试进度值
                if (progressCallback != null) {
                    String songName = new File(completedBPMSongs.get(0).getAudioPath()).getName();
                    File file = new File(completedBPMSongs.get(0).getAudioPath());
                    try {
                        String progressMessage = "已完成跑步单曲: " + songName;
                        progressCallback.onProgressUpdate(progressMessage, (int) Math.round(progress), file);
                    } catch (Exception e) {
                        // 如果进度回调抛出异常，可能是任务被取消了
                        LogUtil.error("RunningMusicGenerator.SongProcessingTask", "compute", "进度回调异常，可能任务已被取消: " + e.getMessage());
                        Thread.currentThread().interrupt(); // 设置中断标志
                    }
                }
            } else if (completedBPMSongs.size() > 1) {
                // 分割任务并并行处理
                int mid = completedBPMSongs.size() / 2;

                // 创建左右子任务的原始索引列表
                List<Integer> leftOriginalIndices = new ArrayList<>();
                List<Integer> rightOriginalIndices = new ArrayList<>();

                for (int i = 0; i < mid; i++) {
                    leftOriginalIndices.add(originalIndices.get(i));
                }
                for (int i = mid; i < completedBPMSongs.size(); i++) {
                    rightOriginalIndices.add(originalIndices.get(i));
                }

                SongProcessingTask leftTask = new SongProcessingTask(params, completedBPMSongs.subList(0, mid), outerInstance, progressCallback);
                SongProcessingTask rightTask = new SongProcessingTask(params, completedBPMSongs.subList(mid, completedBPMSongs.size()), outerInstance, progressCallback);

                // 设置原始索引列表
                leftTask.originalIndices.clear();
                leftTask.originalIndices.addAll(leftOriginalIndices);
                rightTask.originalIndices.clear();
                rightTask.originalIndices.addAll(rightOriginalIndices);

                // 检查中断状态和停止标志
                try {
                    // 直接访问外部类实例的isStopping字段
                    boolean isStopping = outerInstance.isStopping;

                    if (Thread.currentThread().isInterrupted() || isStopping) {
                        LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "compute", "任务被中断，取消任务分割");
                        return;
                    }
                } catch (Exception e) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "compute", "检查停止标志时出错: " + e.getMessage());
                }

                // 递归执行子任务
                leftTask.fork();
                rightTask.compute();
                leftTask.join();
            }
        }

        private Song processSong(Song song) {
            try {
                int offetMs = 80;
                // 检查线程是否被中断
                if (Thread.currentThread().isInterrupted()) {
                    LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "处理歌曲时检测到中断信号");
                    return null;
                }

                // 检查外部停止标志
                try {
                    // 直接访问外部类实例的isStopping字段
                    boolean isStopping = outerInstance.isStopping;

                    if (isStopping) {
                        LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "收到停止信号，正在退出...");
                        return null;
                    }
                } catch (Exception e) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "检查停止标志时出错: " + e.getMessage());
                }

                // 检查song对象是否为null
                if (song == null) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "错误：歌曲对象为null");
                    return null;
                }

                // 检查audioPath是否为null
                if (song.getAudioPath() == null) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "错误：歌曲音频路径为null");
                    return null;
                }

                // 检查BPM是否有效
                if (song.getBpm() <= 0) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "错误：歌曲BPM值无效: " + song.getBpm());
                    return null;
                }

                // 检查时长是否有效
                if (song.getDuration() <= 0) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "错误：歌曲时长无效: " + song.getDuration());
                    return null;
                }


                // 获取原始音频文件名（去除后缀）
                File audioFile = new File(song.getAudioPath());
                String fileName = audioFile.getName();

                // 检查文件是否存在
                if (!audioFile.exists()) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "错误：音频文件不存在: " + song.getAudioPath());
                    return null;
                }

                // 检查文件名是否包含扩展名
                if (fileName.lastIndexOf('.') <= 0) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "错误：无法解析文件名 " + fileName + " 的扩展名");
                    return null;
                }

                String baseName = fileName.substring(0, fileName.lastIndexOf('.'));

                // 生成输出文件名
                // 如果targetBpm为-1，表示保持原速，使用原始BPM值
                double actualTargetBpm = (targetBpm == -1) ? song.getBpm() : targetBpm;
                // 新的文件名格式：歌曲名-步频-节拍音效索引-节拍音量-背景音量.wav
                String newFileName = baseName + "-" + String.format("%.0f", actualTargetBpm) + "-" + beatSoundType + "-" + String.format("%.2f", beatVolume) + "-" + String.format("%.2f", backgroundVolume);
                File finalOutputDir = new File(outputDir, "run_single");
                finalOutputDir.mkdirs();
                String finalOutputPath = finalOutputDir.getAbsolutePath() + File.separator + newFileName + ".wav";

                // 检查文件是否已经存在
                File outputFile = new File(finalOutputPath);
                if (outputFile.exists()) {

                    // 创建新的Song对象来存储处理后的信息
                    Song processedSong = new Song();
                    processedSong.setAudioPath(finalOutputPath);
                    processedSong.setFileName(newFileName);

                    // 重新计算鼓点和时长（与正常处理时相同）
                    double originalBpm = song.getBpm();
                    double speedMultiplier = BeatPreprocessor.calculateSpeedMultiplier(originalBpm, actualTargetBpm);
                    int adjustedDuration = (int) (song.getDuration() / speedMultiplier);//得到变速后的时长
                    int adjustedBeatOffset = (int) Math.round(song.getBeatOffset() / speedMultiplier);
                    // 根据变速后的偏移生成均匀的鼓点
                    List<Integer> alignedBeats = BeatDetector.generateUniformBeats(
                            actualTargetBpm, adjustedDuration, adjustedBeatOffset);

                    // 计算静音时间
                    int[] silenceDurations = calculateSilenceDurations(alignedBeats, offetMs, adjustedDuration);
                    int startSilenceMs = silenceDurations[0];
                    int endSilenceMs = silenceDurations[1];

                    // 但在Song对象中需要包含静音段的时长
                    int totalDurationWithSilence = startSilenceMs + endSilenceMs + adjustedDuration;//获取总时长

                    if (!alignedBeats.isEmpty()) {
                        processedSong.setBeatOffset(alignedBeats.get(0));
                    } else {
                        processedSong.setBeatOffset(0);
                    }
                    processedSong.setBpm(actualTargetBpm);
                    processedSong.setDuration(totalDurationWithSilence);

                    // 添加处理后音频路径与原始音频路径的映射关系
                    audioPathMapping.put(finalOutputPath, song.getAudioPath());

                    return processedSong;
                }

                // 文件不存在，继续正常处理流程
                // 初始化处理类
                BeatPreprocessor preprocessor = new BeatPreprocessor();

                double originalBpm = song.getBpm();
                // 1. 生成变速鼓点
                // 计算变速倍数
                // 如果targetBpm为-1，表示保持原速，使用原始BPM值
                double actualTargetBpmForCalc = (targetBpm == -1) ? originalBpm : targetBpm;
                double speedMultiplier = preprocessor.calculateSpeedMultiplier(originalBpm, actualTargetBpmForCalc);

                // 计算变速后的时长
                int adjustedDuration = (int) (song.getDuration() / speedMultiplier);
                LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "调整后时长: " + adjustedDuration + "ms");

                // 获取偏移值
                LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "获取偏移值...");
                int adjustedBeatOffset = (int) Math.round(song.getBeatOffset() / speedMultiplier);
                // 根据变速后的偏移生成均匀的鼓点
                List<Integer> alignedBeats = BeatDetector.generateUniformBeats(
                        actualTargetBpm, adjustedDuration, adjustedBeatOffset);
                LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "均匀鼓点数量: " + alignedBeats.size());
                LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "均匀鼓点: " + alignedBeats.subList(0, Math.min(10, alignedBeats.size())) +
                        (alignedBeats.size() > 10 ? "..." : ""));
                // 打印变速倍数和调整后的鼓点
                LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "原始BPM: " + originalBpm + ", 目标BPM: " + actualTargetBpmForCalc + ", 变速倍数: " + speedMultiplier + ", 均匀鼓点数量: " + alignedBeats.size());

                // 检查线程是否被中断
                if (Thread.currentThread().isInterrupted()) {
                    LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "处理歌曲时检测到中断信号");
                    return null;
                }

                // 检查外部停止标志
                try {
                    // 直接访问外部类实例的isStopping字段
                    boolean isStopping = outerInstance.isStopping;

                    if (isStopping) {
                        LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "收到停止信号，正在退出...");
                        return null;
                    }
                } catch (Exception e) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "检查停止标志时出错: " + e.getMessage());
                }

                // 2. 将音频进行变速和叠加鼓点
                // 使用TimeStretchProcessor实现不变调的变速
                byte[] speedPcmToBytes = AudioSpeedChanger.changeSpeedWithoutPitch(audioFile, speedMultiplier);
                //2.4 将pcm数据进行叠加鼓点
                //2.4.1 设置鼓点类型和音量
                //根据鼓点类型索引获取鼓点pcm音效文件
                byte[] beatSoundPcm = BeatOverlayProcessor.getBeatSoundPcm(beatSoundType);
                //设置鼓点音量
                beatSoundPcm = PCMAudioProcessor.adjustPCMVolume(beatSoundPcm, beatVolume);
                
                // 调整背景音乐音量
                speedPcmToBytes = PCMAudioProcessor.adjustPCMVolume(speedPcmToBytes, backgroundVolume);
                
                //将变速后的PCM叠加上鼓点音效
                byte[] beatSoundPcmToBytes = BeatOverlayProcessor.overlayBeatSoundOnPcm(speedPcmToBytes, beatSoundPcm, alignedBeats);
                // 2.5. 计算开始和结尾需要增加的静音时间MS
                int[] silenceDurations = calculateSilenceDurations(alignedBeats, offetMs, adjustedDuration);
                int startSilenceMs = silenceDurations[0];
                int endSilenceMs = silenceDurations[1];

                //2.6. 添加开始和结尾的静音
                beatSoundPcmToBytes = PCMAudioProcessor.addSilenceToPcm(beatSoundPcmToBytes, startSilenceMs, endSilenceMs);
                //2.7. 将PCM数据转换为WAV数据
                byte[] outWavToBytes = AudioTranscoder.wrapPCMAsWAV(beatSoundPcmToBytes);
                //2.8. 将wav数据直接写入最终输出文件
                File finalOutputFile = new File(finalOutputPath);

                // 确保输出目录存在
                finalOutputFile.getParentFile().mkdirs();
                AudioTranscoder.writeBytesToFile(outWavToBytes, finalOutputFile);
                // 更新最终时长，包含静音段
                adjustedDuration = startSilenceMs + endSilenceMs + adjustedDuration;

                LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "成功生成最终单曲音频: " + finalOutputPath);
                writeProcessingLog("音频处理完成", "最终输出文件: " + finalOutputPath + ", 文件大小: " + (new File(finalOutputPath).exists() ? new File(finalOutputPath).length() : "N/A"));

                // 检查线程是否被中断
                if (Thread.currentThread().isInterrupted()) {
                    LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "处理歌曲时检测到中断信号");
                    return null;
                }

                // 检查外部停止标志
                try {
                    // 直接访问外部类实例的isStopping字段
                    boolean isStopping = outerInstance.isStopping;

                    if (isStopping) {
                        LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "收到停止信号，正在退出...");
                        return null;
                    }
                } catch (Exception e) {
                    LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "检查停止标志时出错: " + e.getMessage());
                }

                // 5. 创建新的Song对象来存储处理后的信息
                Song processedSong = new Song();
                processedSong.setAudioPath(finalOutputPath); // 使用最终输出路径
                processedSong.setFileName(newFileName);

                processedSong.setBeatOffset(0);
                processedSong.setBpm(actualTargetBpmForCalc);
                processedSong.setDuration(adjustedDuration); // 使用包含静音段的总时长

                // 添加处理后音频路径与原始音频路径的映射关系
                audioPathMapping.put(finalOutputPath, song.getAudioPath());

                LogUtil.debug("RunningMusicGenerator.SongProcessingTask", "processSong", "完成处理歌曲: " + finalOutputPath);
                return processedSong;
            } catch (Exception e) {
                LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "处理歌曲时出错: " + e.getMessage());
                LogUtil.error("RunningMusicGenerator.SongProcessingTask", "processSong", "处理歌曲时出错的堆栈信息: " + java.util.Arrays.toString(e.getStackTrace()));
                // 如果是中断异常，重新抛出中断信号
                if (e instanceof InterruptedException) {
                    Thread.currentThread().interrupt();
                }
                return null;
            }
        }
    }

    /**
     * 计算开头和结尾需要增加的静音时间
     *
     * @param beats            变速后的鼓点列表
     * @param offsetMs         偏移量（毫秒）
     * @param adjustedDuration 变速后的音频时长（毫秒）
     * @return 数组，第一个元素是开头静音时间，第二个元素是结尾静音时间
     */
    private static int[] calculateSilenceDurations(List<Integer> beats, int offsetMs, int adjustedDuration) {
        if (beats.size() < 2) {
            // 如果鼓点不足两个，默认开头和结尾静音时间为0
            return new int[]{0, 0};
        }

        // 计算鼓点间隔
        int lastBeat = beats.get(beats.size() - 1);
        int secondLastBeat = beats.get(beats.size() - 2);
        int beatInterval = lastBeat - secondLastBeat;

        // 计算开头静音时间
        int firstBeatWithOffset = beats.get(0) + offsetMs;
        int startSilenceMs = beatInterval - firstBeatWithOffset;
        startSilenceMs = Math.max(0, startSilenceMs); // 确保不为负数

        // 计算结尾静音时间
        int lastBeatWithOffset = lastBeat + offsetMs;
        int endSilenceMs = beatInterval - (adjustedDuration - lastBeatWithOffset);
        endSilenceMs = Math.max(0, endSilenceMs); // 确保不为负数

        return new int[]{startSilenceMs, endSilenceMs};
    }

    /**
     * 筛选符合尺寸要求的图片文件
     *
     * @param imageFiles     图片文件列表
     * @param requiredWidth  所需宽度
     * @param requiredHeight 所需高度
     * @return 符合尺寸要求的图片文件列表
     */
    private List<File> filterValidImages(File[] imageFiles, int requiredWidth, int requiredHeight) {
        List<File> validImages = new ArrayList<>();
        if (imageFiles != null) {
            for (File imageFile : imageFiles) {
                try {
                    BufferedImage image = ImageIO.read(imageFile);
                    if (image != null) {
                        // 检查图片尺寸是否符合要求（宽度和高度都必须大于等于所需尺寸）
                        if (image.getWidth() >= requiredWidth && image.getHeight() >= requiredHeight) {
                            validImages.add(imageFile);
                        }
                    }
                } catch (IOException e) {
                    LogUtil.error("RunningMusicGenerator", "filterValidImages", "读取图片时出错: " + imageFile.getAbsolutePath());
                }
            }
        }
        return validImages;
    }


    /**
     * 创建跑步视频
     */
    private void createRunningVideo(SongMetadataExtractor.AnalysisProgressCallback progressCallback) throws Exception {
        LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "开始创建跑步视频...");
        String mixAudioPath = mixResult.getMixAudioPath();
        File runVideoDir = new File(outputDir, "run_video");
        runVideoDir.mkdirs();

        // 如果targetBpm为-1，表示保持原速，使用"original"作为标识
        String bpmLabel = (targetBpm == -1) ? "original" : String.format("%.0f", targetBpm);
        // 使用更易读的日期时间格式生成文件名
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
        String timestamp = dateFormat.format(new Date());
        File outputVideoPath = new File(runVideoDir, "BPM" + bpmLabel + "VIDEO_" + timestamp + ".mp4");

        // 根据视频分辨率设置宽高
        int width, height;
        switch (videoResolution) {
            case "720p":
                if (isLandscape) {
                    width = 1280;
                    height = 720;
                } else {
                    width = 720;
                    height = 1280;
                }
                break;


            case "1080p":
            default:
                if (isLandscape) {
                    width = 1920;
                    height = 1080;
                } else {
                    width = 1080;
                    height = 1920;
                }
                break;
        }

        // 添加进度回调：开始生成视频
        if (progressCallback != null) {
            progressCallback.onProgressUpdate("正在生成视频...", 0, null);
        }

        String backgroundColorImagePath = null; // 用于记录生成的纯色背景图片路径，以便后续删除

        try {
            // 根据视频样式参数决定使用哪种渲染器
            boolean generateSpectrumVideo = "spectrum".equals(videoStyle); // 如果视频样式为"spectrum"则使用频谱渲染器
            boolean generateCircularSpectrumVideo = "circular".equals(videoStyle); // 如果视频样式为"circular"则使用圆环式频谱渲染器
            boolean generateStarlightSpectrumVideo = "starlight".equals(videoStyle); // 如果视频样式为"starlight"则使用频谱星光渲染器

            LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "视频样式设置 - 普通频谱: " + generateSpectrumVideo +
                    ", 圆环频谱: " + generateCircularSpectrumVideo + ", 星光频谱: " + generateStarlightSpectrumVideo);

            if (generateSpectrumVideo || generateCircularSpectrumVideo || generateStarlightSpectrumVideo) {
                // 使用新的视频生成调度器处理频谱视频
                String spectrumStyle = generateSpectrumVideo ? "spectrum" :
                        generateCircularSpectrumVideo ? "circular" : "starlight";

                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "开始调用VideoGenerationScheduler.generateSpectrumVideo");
                // 打印传入前的时长信息
                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "传入VideoGenerationScheduler前的时长信息 - mixResult.getTotalDuration(): " + mixResult.getTotalDuration() + "ms");
                // 按照正确的流程，传递音频文件路径而不是音频数据
                boolean result = VideoGenerationScheduler.generateSpectrumVideo(
                        mixResult.getMixAudioPath(), // 传递音频文件路径
                        mixResult.getTotalDuration(),
                        outputVideoPath.getAbsolutePath(),
                        width,
                        height,
                        mixResult.getDisplayListContent(),
                        params.getVideoTitle(),
                        spectrumStyle,
                        new ProgressCallback() {
                            @Override
                            public void onProgress(String message, double progress) {
                                if (progressCallback != null) {
                                    progressCallback.onProgressUpdate("生成视频: " + message, (int) Math.round(progress), null);
                                }
                                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "频谱视频生成进度: " + message + ", " + progress + "%");
                            }
                        });

                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "VideoGenerationScheduler.generateSpectrumVideo调用完成，结果: " + result);
                if (!result) {
                    throw new Exception("频谱视频生成失败");
                }
            } else {
                // 使用原来的VideoGenerator生成视频（图片轮播）
                // 只有在不使用频谱视频渲染器时才执行图片下载和叠加文字操作

                // 添加进度回调：开始下载图片
                if (progressCallback != null) {
                    progressCallback.onProgressUpdate("正在下载图片资源...", 0, null);
                }

                // 在输出目录下创建图片文件夹（用于下载原始图片）
                File imageDownloadDir = new File(outputDir, "images");
                if (!imageDownloadDir.exists()) {
                    imageDownloadDir.mkdirs();
                }

                // 在临时目录下创建图片文件夹（用于保存叠加文字的图片）
                File imageOverlayDir = new File(tempDir, "images");
                if (!imageOverlayDir.exists()) {
                    imageOverlayDir.mkdirs();
                }

                // 扫描文件夹获取图片列表
                List<File> imageFiles = new ArrayList<>();
                File[] allImageFiles = imageDownloadDir.listFiles((dir, name) ->
                        name.toLowerCase().endsWith(".jpg") ||
                                name.toLowerCase().endsWith(".png") ||
                                name.toLowerCase().endsWith(".jpeg"));

                // 将所有图片文件添加到列表
                if (allImageFiles != null) {
                    Collections.addAll(imageFiles, allImageFiles);
                }

                // 筛选符合尺寸要求的图片
                List<File> validImageFiles = filterValidImages(allImageFiles, width, height);

                // 检查符合尺寸要求的图片数量是否足够
                if (validImageFiles.size() < mixResult.getFinalSelectedSongs().size()) {
                    LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "符合尺寸要求的图片数量不足，需要下载图片... 目标图片数量: " + mixResult.getFinalSelectedSongs().size() + ", 当前符合尺寸要求的图片数量: " + validImageFiles.size() + ", 即将下载图片到目录: " + imageDownloadDir.getAbsolutePath() + ", 下载图片尺寸: " + width + "x" + height);

                    // 下载图片
                    ImageCrawler imageCrawler = new ImageCrawler(imageDownloadDir.getAbsolutePath(), width, height);
                    imageCrawler.crawlAndSaveImages(mixResult.getFinalSelectedSongs().size());

                    // 等待4秒，让图片下载完成
                    LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "等待4秒让图片下载完成...");
                    Thread.sleep(4000);

                    // 清空原有列表，重新扫描文件夹
                    imageFiles.clear();
                    allImageFiles = imageDownloadDir.listFiles((dir, name) ->
                            name.toLowerCase().endsWith(".jpg") ||
                                    name.toLowerCase().endsWith(".png") ||
                                    name.toLowerCase().endsWith(".jpeg"));

                    // 重新加载图片列表
                    if (allImageFiles != null) {
                        Collections.addAll(imageFiles, allImageFiles);
                    }

                    // 再次筛选符合尺寸要求的图片
                    validImageFiles = filterValidImages(allImageFiles, width, height);
                }

                // 记录生成的纯色背景图片路径，以便后续删除

                // 检查是否有符合尺寸要求的图片，如果没有则生成一张纯色图
                if (validImageFiles.isEmpty()) {
                    LogUtil.error("RunningMusicGenerator", "createRunningVideo", "没有可用的符合尺寸要求的图片，将生成纯色背景图片");

                    // 添加进度回调：生成纯色背景
                    if (progressCallback != null) {
                        progressCallback.onProgressUpdate("正在生成默认背景图片...", (int) (100.0 / 4), null);
                    }

                    // 生成纯色背景图片
                    backgroundColorImagePath = imageDownloadDir.getAbsolutePath() + File.separator + "background_color.png";
                    BufferedImage backgroundColorImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                    // 填充为黑色背景
                    Graphics2D g2d = backgroundColorImage.createGraphics();
                    g2d.setColor(Color.BLACK);
                    g2d.fillRect(0, 0, width, height);
                    g2d.dispose();

                    // 保存纯色背景图片
                    ImageIO.write(backgroundColorImage, "png", new File(backgroundColorImagePath));

                    // 清空列表并重新扫描
                    imageFiles.clear();
                    allImageFiles = imageDownloadDir.listFiles((dir, name) ->
                            name.toLowerCase().endsWith(".jpg") ||
                                    name.toLowerCase().endsWith(".png") ||
                                    name.toLowerCase().endsWith(".jpeg"));

                    // 重新加载图片列表
                    if (allImageFiles != null) {
                        Collections.addAll(imageFiles, allImageFiles);
                    }

                    // 再次筛选符合尺寸要求的图片（现在应该包含纯色背景图片）
                    validImageFiles = filterValidImages(allImageFiles, width, height);
                }

                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "最终符合尺寸要求的图片数量: " + validImageFiles.size());

                // 使用ImageTextOverlay将图片叠加上文字
                // 这里需要获取显示列表文件路径
                File runMixDir = new File(outputDir, "run_mix");
                File playlistFile = new File(runMixDir, "playlist.m3u");

                // 不再使用图片叠加文字，而是直接使用原始图片并结合VideoUIUtils绘制播放列表
                List<String> overlayImagePaths = new ArrayList<>();
                
                // 直接使用原始图片路径，不进行文字叠加
                for (int i = 0; i < validImageFiles.size(); i++) {
                    String imagePath = validImageFiles.get(i).getAbsolutePath();
                    overlayImagePaths.add(imagePath);
                }
                
                // 添加进度回调：生成纯色背景
                if (progressCallback != null) {
                    int progressValue = (int) ((100 * 1.0 / 4) + (validImageFiles.size() * 100.0 / validImageFiles.size()) * 1.0 / 4);
                    progressCallback.onProgressUpdate("正在处理图片...", progressValue, null);
                }
                
                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "图片处理完成，处理后的图片数量: " + overlayImagePaths.size());

                // 打乱图片顺序，避免每次图片顺序相同（仅当有多个图片时）
                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "处理前的图片数量: " + overlayImagePaths.size());
                if (overlayImagePaths.size() > 1) {
                    Collections.shuffle(overlayImagePaths);
                    LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "打乱图片顺序完成");
                }

                // 使用新的PlaylistOverlayVideoGenerator来生成带有播放列表的图片轮播视频
                PlaylistOverlayVideoGenerator videoGenerator = new PlaylistOverlayVideoGenerator(
                    overlayImagePaths, 
                    mixResult.getDisplayListContent(), 
                    mixAudioPath, 
                    outputVideoPath.getAbsolutePath(), 
                    params.getVideoTitle(),
                    width, 
                    height
                );
                // 这里需要获取总时长
                int totalDuration = mixResult.getFinalSelectedSongs().stream().mapToInt(Song::getDuration).sum();
                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "视频总时长: " + totalDuration + "ms");

                boolean result = false;
                // 图片轮播视频不使用分段处理模式，因为和视频渲染类原理不同会出错
                if ("slideshow".equals(videoStyle)) {
                    LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "使用常规处理模式生成图片轮播视频");
                    result = videoGenerator.generateVideoWithMultipleImagesAndPlaylist(totalDuration, 3000, new ProgressCallback() {
                        @Override
                        public void onProgress(String message, double progress) {
                            // 将子任务进度映射到主进度的范围 (85-95%)
                            double mappedProgress = 100 * 2.0 / 4 + progress * 2.0 / 4;
                            if (progressCallback != null) {
                                progressCallback.onProgressUpdate("生成视频: " + message, (int) Math.round(mappedProgress), null);
                            }
                        }
                    });
                } else {
                    // 频谱视频使用VideoGenerationScheduler
                    LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "使用VideoGenerationScheduler生成频谱视频");
                    result = VideoGenerationScheduler.generateSpectrumVideo(
                            mixAudioPath,
                            totalDuration,
                            outputVideoPath.getAbsolutePath(),
                            width,
                            height,
                            mixResult.getDisplayListContent(),
                            params.getVideoTitle(),
                            videoStyle,
                            new ProgressCallback() {
                                @Override
                                public void onProgress(String message, double progress) {
                                    if (progressCallback != null) {
                                        progressCallback.onProgressUpdate("生成视频: " + message, (int) Math.round(progress), null);
                                    }
                                    LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "频谱视频生成进度: " + message + ", " + progress + "%");
                                }
                            });
                }

                LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "PlaylistOverlayVideoGenerator.generateVideoWithMultipleImagesAndPlaylist调用完成，结果: " + result);
                if (!result) {
                    throw new Exception("PlaylistOverlayVideoGenerator生成视频失败");
                }

                // 如果生成了纯色背景图片，则在视频生成完成后删除它
                if (backgroundColorImagePath != null) {
                    try {
                        File backgroundColorImageFile = new File(backgroundColorImagePath);
                        if (backgroundColorImageFile.exists()) {
                            Files.delete(backgroundColorImageFile.toPath());
                            LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "已删除生成的纯色背景图片: " + backgroundColorImagePath);
                        }
                    } catch (IOException e) {
                        LogUtil.error("RunningMusicGenerator", "createRunningVideo", "删除纯色背景图片时出错: " + e.getMessage());
                    }
                }
            }

            // 添加进度回调：视频生成完成
            LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "视频生成流程完成，准备调用完成回调");
            if (progressCallback != null) {
                progressCallback.onProgressUpdate("视频生成完成", 100, null);
            }
            LogUtil.debug("RunningMusicGenerator", "createRunningVideo", "完成回调调用完成");
        } catch (Exception e) {
            LogUtil.error("RunningMusicGenerator", "createRunningVideo", "生成视频时出错: " + e.getMessage());
            LogUtil.error("RunningMusicGenerator", "createRunningVideo", "生成视频时出错的堆栈信息: " + java.util.Arrays.toString(e.getStackTrace()));
            throw new Exception("生成视频时出错", e);
        }
    }


    /**
     * 写入处理调试日志
     */
    private static void writeProcessingLog(String operation, String details) {
        String MD = RunningMusicGenerator.class.getSimpleName();
        LogUtil.debug(MD, operation, details);
    }

    /**
     * 生成音频文件列表的签名
     *
     * @param audioFiles 音频文件列表
     * @return 签名字符串
     */
    private String generateAudioListSignature(List<File> audioFiles) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 将所有音频文件路径拼接起来
            StringBuilder sb = new StringBuilder();
            for (File file : audioFiles) {
                sb.append(file.getAbsolutePath());
                // 添加文件最后修改时间，确保文件内容变化时签名也会变化
                sb.append(file.lastModified());
            }

            byte[] digest = md.digest(sb.toString().getBytes());

            // 将字节数组转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            LogUtil.error("RunningMusicGenerator", "generateAudioListSignature", "生成签名时出错: " + e.getMessage());
            return null;
        }
    }

    /**
     * 从缓存中获取已合并的音频文件路径
     *
     * @param signature 音频文件列表签名
     * @return 已合并的音频文件路径，如果不存在则返回null
     */
    private String getCachedMergedAudioPath(String signature) {
        try {
            AppDataManager appDataManager = AppDataManager.getInstance();
            Path appDataDir = appDataManager.getAppDataDirectory();
            Path cacheDir = appDataDir.resolve("audio_cache");

            // 确保缓存目录存在
            Files.createDirectories(cacheDir);

            // 创建缓存文件路径
            Path cacheFile = cacheDir.resolve("merged_audio_cache.json");

            // 检查缓存文件是否存在
            if (Files.exists(cacheFile)) {
                // 从JSON文件读取缓存映射
                Type type = new TypeToken<Map<String, String>>() {
                }.getType();
                Map<String, String> cacheMap = JsonUtils.readFromJson(cacheFile.toString(), type);

                if (cacheMap != null && cacheMap.containsKey(signature)) {
                    String cachedPath = cacheMap.get(signature);

                    // 检查缓存的文件是否存在
                    if (cachedPath != null) {
                        File cachedFile = new File(cachedPath);
                        if (cachedFile.exists()) {
                            return cachedPath;
                        } else {
                            // 如果文件不存在，从缓存中移除
                            cacheMap.remove(signature);
                            JsonUtils.writeToJson(cacheMap, cacheFile.toString());
                        }
                    }
                }
            }
        } catch (Exception e) {
            LogUtil.error("RunningMusicGenerator", "getCachedMergedAudioPath", "获取缓存路径时出错: " + e.getMessage());
        }

        return null;
    }

    /**
     * 将合并后的音频文件路径保存到缓存
     *
     * @param signature       音频文件列表签名
     * @param mergedAudioPath 合并后的音频文件路径
     */
    private void saveMergedAudioPathToCache(String signature, String mergedAudioPath) {
        try {
            AppDataManager appDataManager = AppDataManager.getInstance();
            Path appDataDir = appDataManager.getAppDataDirectory();
            Path cacheDir = appDataDir.resolve("audio_cache");

            // 确保缓存目录存在
            Files.createDirectories(cacheDir);

            // 创建缓存文件路径
            Path cacheFile = cacheDir.resolve("merged_audio_cache.json");

            // 读取现有的缓存映射或创建新的
            Map<String, String> cacheMap;
            Type type = new TypeToken<Map<String, String>>() {
            }.getType();

            if (Files.exists(cacheFile)) {
                cacheMap = JsonUtils.readFromJson(cacheFile.toString(), type);
            } else {
                cacheMap = new HashMap<>();
            }

            if (cacheMap == null) {
                cacheMap = new HashMap<>();
            }

            // 更新缓存映射
            cacheMap.put(signature, mergedAudioPath);

            // 保存到JSON文件
            JsonUtils.writeToJson(cacheMap, cacheFile.toString());
        } catch (Exception e) {
            LogUtil.error("RunningMusicGenerator", "saveMergedAudioPathToCache", "保存缓存路径时出错: " + e.getMessage());
        }
    }

}

